/*
 * Project: a2
 * Copyright (C) 2008 ralfoide gmail com,
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.alfray.a2.engine;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import com.alfray.a2.gameplay.SpriteState;

class SpriteGL {

    private IntBuffer xVertexBuffer;
    private IntBuffer xTexBuffer;
    private ShortBuffer mIndexBuffer;

    private final static int VERTS = 6;

    public SpriteGL(int sx, int sy, float textureScale) {

        // Buffers to be passed to gl*Pointer() functions
        // must be direct, i.e., they must be placed on the
        // native heap where the garbage collector cannot
        // move them.
        //
        // Buffers with multi-byte datatypes (e.g., short, int, float)
        // must have their byte order set to native order

        ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
        vbb.order(ByteOrder.nativeOrder());
        xVertexBuffer = vbb.asIntBuffer();

        ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);
        tbb.order(ByteOrder.nativeOrder());
        xTexBuffer = tbb.asIntBuffer();

        ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
        ibb.order(ByteOrder.nativeOrder());
        mIndexBuffer = ibb.asShortBuffer();

        // A unit-sided square centered on the origin.
        int[] coords = {
                        // for vertexes: X, Y,
                        // for textures: U, V, ignored
                        // Points are described CCW (X is to the right and Y is up)
                        0, 0,
                        1, 0,
                        0, 1,

                        1, 0,
                        1, 1,
                        0, 1,
        };

        int isx = sx << 16;
        int isy = sy << 16;

        for (int i = 0; i < VERTS; i++) {
            xVertexBuffer.put((int) (isx * (coords[i*2+0] - 0.5f)));
            xVertexBuffer.put((int) (isy * (coords[i*2+1] - 0.5f)));
            xVertexBuffer.put(0); // Z==0
        }

        // Adjust texture coordinates account to texture scale
        isx = (int)(isx * textureScale);
        isy = (int)(isy * textureScale);

        // We invert textures in Y because all the graphics assume
        // Y towards bottom whereas GL uses Y towards top.
        for (int i = 0; i < VERTS; i++) {
            xTexBuffer.put(isx *      coords[i*2+0] );
            xTexBuffer.put(isy * (1 - coords[i*2+1]));
        }

        for(int i = 0; i < VERTS; i++) {
            mIndexBuffer.put((short) i);
        }

        xVertexBuffer.position(0);
        xTexBuffer.position(0);
        mIndexBuffer.position(0);
    }

    public void draw(GL10 gl, SpriteState state, int xAutoAngle, int xRotZAngle) {
        int effects = state.mGlEffect;
        if (xRotZAngle != 0) effects |= SpriteState.ROT_Z;

        // Note: doing a glPushMatrix on all 42 sprites reduces the fps from 33 to 27.
        // So we need to be extra careful here and avoid changing state unless really necessary.
        boolean didPush = false;

        if (effects != SpriteState.NO_EFFECT) {
            gl.glPushMatrix();
            didPush = true;

            if ((effects & SpriteState.TRANSLATE) != 0) {
                gl.glTranslatex(state.xOffsetX, state.xOffsetY, 0);
            }

            if ((effects & SpriteState.ROT_Y) != 0) {
                gl.glRotatex(state.xRotY, 0, 1<<16, 0);
            } else if ((effects & SpriteState.AUTO_ROT_Y) != 0) {
                gl.glRotatex(xAutoAngle * state.mFactorAutoRotY, 0, 1<<16, 0);
            }
            if ((effects & SpriteState.ROT_Z) != 0) {
                gl.glRotatex(xRotZAngle + state.xRotZ, 0, 0, 1<<16);
            }

            if ((effects & SpriteState.ZOOM) != 0) {
                int k = state.xZoomXY;
                gl.glScalex(k, k, 0);
            }
        }

        int[] col = state.mColor;
        if (col != null) {
            gl.glColor4x(col[0], col[1], col[2], col[3]);
        }

        gl.glFrontFace(GL10.GL_CCW);
        gl.glVertexPointer(3, GL10.GL_FIXED, 0, xVertexBuffer);
        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, xTexBuffer);
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS, GL10.GL_UNSIGNED_SHORT, mIndexBuffer);

        if (didPush) gl.glPopMatrix();
    }

}
